package ljl.alg.codec;

import java.util.zip.CRC32;

public class CrcLearn {
    
    static int crc32v1(int b) {
        int crc = 0xFFFFFFFF;
        b = Integer.reverse(b); // 32-bit reversal.
        for (int j = 0; j <= 7; j++) { // Do eight times.
            if ((crc ^ b) < 0) crc = (crc << 1) ^ 0x04C11DB7;
            else crc = crc << 1;
            b = b << 1; // Ready next msg bit.
        }
        return Integer.reverse(~crc);
    }
    
    static int crc32v2(int b) {
        int crc = ~b;
        for (int j = 7; j >= 0; j--) { // Do eight times.
            int mask = -(crc & 1); // 根据最低位判断是异或还是只位移：如果是 1，需要异或再位移；如果是 0，只位移
            crc = (crc >>> 1) ^ (0xEDB88320 & mask); // 这个 poly 被反转了，看清楚
        }
        return ~crc;
    }
    
    static int[] table = new int[256];
    static {
        for (int b = 0; b <= 255; b++) {
            int crc = b;
            for (int j = 7; j >= 0; j--) { // Do eight times.
                int mask = -(crc & 1);
                crc = (crc >>> 1) ^ (0xEDB88320 & mask);
            }
            table[b] = crc;
        }
    }
    static int crc32v3(int b) {
        int crc = 0xFFFFFFFF;
        crc = (crc >>> 8) ^ table[(crc ^ b) & 0xFF];
        return ~crc;
    }
    
    public static void main(String[] args) {
        CRC32 c = new CRC32();
        c.update(1);
        System.out.println(Integer.toHexString((int)c.getValue()));
        System.out.println(Integer.toHexString(crc32v1(1)));
        System.out.println(Integer.toHexString(crc32v2(1)));
        System.out.println(Integer.toHexString(crc32v3(1)));
    }
    
    // 下面是 c 实现，省的我写错了
    /*
    unsigned int crc32(unsigned char *message) {
        int i, j;
        unsigned int byte, crc;
        i = 0;
        crc = 0xFFFFFFFF;
        while (message[i] != 0) {
            byte = message[i]; // Get next byte.
            byte = reverse(byte); // 32-bit reversal.
            for (j = 0; j < = 7; j++) { // Do eight times.
                if ((int)(crc ^ byte) < 0) crc = (crc << 1) ^ 0x04C11DB7;
                else crc = crc << 1;
                byte = byte << 1; // Ready next msg bit.
            }
            i = i + 1;
        }
        return reverse(~crc);
    }

    unsigned reverse(unsigned x) {
        x = (x & 0x55555555) << 1 | (x >> 1) & 0x55555555;
        x = (x & 0x33333333) << 2 | (x >> 2) & 0x33333333;
        x = (x & 0x0F0F0F0F) << 4 | (x >> 4) & 0x0F0F0F0F;
        x = (x << 24) | ((x & 0xFF00) << 8) | ((x >> 8) & 0xFF00) | (x >> 24);
        return x;
    }

    unsigned int crc32(unsigned char *message) {
        int i, j;
        unsigned int byte, crc, mask;
        i = 0;
        crc = 0xFFFFFFFF;
        while (message[i] != 0) {
            byte = message[i]; // Get next byte.
            crc = crc ^ byte;
            for (j = 7; j >= 0; j--) { // Do eight times.
                mask = -(crc & 1);
                crc = (crc >> 1) ^ (0xEDB88320 & mask);
            }
            i = i + 1;
        }
        return ~crc;
    }
    
    unsigned int crc32(unsigned char *message) {
        int i, j;
        unsigned int byte, crc, mask;
        static unsigned int table[256];
        // Set up the table, if necessary.
        if (table[1] == 0) {
            for (byte = 0; byte <= 255; byte++) {
                crc = byte;
                for (j = 7; j >= 0; j--) { // Do eight times.
                    mask = -(crc & 1);
                    crc = (crc >> 1) ^ (0xEDB88320 & mask);
                }
                table[byte] = crc;
            }
        }
        // Through with table setup, now calculate the CRC.
        i = 0;
        crc = 0xFFFFFFFF;
        while ((byte = message[i]) != 0) {
            crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF];
            i = i + 1;
        }
        return ~crc;
    }
*/
}
